// 标准C库文件
#include <stdio.h>
#include <string.h>
#include <cstdlib>

// CTP头文件
#include <ThostFtdcTraderApi.h>
#include <ThostFtdcMdApi.h>
#include <ThostFtdcUserApiDataType.h>
#include <ThostFtdcUserApiStruct.h>

// 线程控制相关
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>

// 定时器相关
#include <signal.h>
#include <sys/time.h>


// 字符串编码转化
#include <code_convert.h>




// 登录请求结构体
CThostFtdcReqUserLoginField userLoginField;
// 用户请求结构体
CThostFtdcUserLogoutField userLogoutField;
// 线程同步标志
sem_t sem;
// requestID
int requestID = 0;


class CTraderHandler : public CThostFtdcTraderSpi{

	public:

    CTraderHandler(){
        printf("CTraderHandler():被执行...\n");
    }

	// 允许登录事件
    virtual void OnFrontConnected() {
		static int i = 0;
		printf("OnFrontConnected():被执行...\n");
		// 在登出后系统会重新调用OnFrontConnected，这里简单判断并忽略第1次之后的所有调用。
		if (i++==0) {
			sem_post(&sem);
		}
    }

	// 登录结果响应
    virtual void OnRspUserLogin(CThostFtdcRspUserLoginField *pRspUserLogin,
    	CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast){
        printf("OnRspUserLogin():被执行...\n");
		if (pRspInfo->ErrorID == 0) {
			printf("登录成功!\n");
			sem_post(&sem);
		}else{
			printf("登录失败!\n");
		}
    }

	// 登出结果响应
	virtual void OnRspUserLogout(CThostFtdcUserLogoutField *pUserLogout,
		CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {
		printf("OnReqUserLogout():被执行...\n");
		if (pRspInfo->ErrorID == 0) {
			printf("登出成功!\n");
			sem_post(&sem);
		}else{
			printf("登出失败!\n");
		}
	}

	// 错误信息响应方法
	virtual void OnRspError
		(CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast){		
		printf("OnRspError():被执行...\n");
	}


	//{{ onRtnOrderMethod['doxygen'].decode('utf8') }}
    virtual {{ onRtnOrderMethod['returns'] }} {{ onRtnOrderMethod['name'] }}(
        {% for parameter in onRtnOrderParameters -%}
            {{  parameter['type'] }} {{ parameter['name'] -}}
            {% if not loop.last %},{% endif %}
        {% endfor -%}
    ){
		printf("{{ onRtnOrderMethod['name'] }}():被执行...\n");
		// 如果有返回结果读取返回信息
        if ( {{onRtnOrderParameters[0]['name']}} != NULL ) {
            // 读取返回信息,并做编码转化
            {% for field in onRtnOrderFields -%}
                {{field['doxygen'].decode('utf8')}} {{ field['type'] }} {{ field['original'] -}}
                {% if field['len'] %}[{{ field['len'] }}]{% endif %}
                {% if field['enums'] -%}
                    {% for enum in field['enums'] -%}
                        //// {{enum['name']}} {{enum['value']}} {{enum['remark'].decode('utf8')}}
                    {% endfor -%}
                {% endif -%}
                {% if field['original'] == 'char' and field['len'] != None -%}
                    {{field['original']}} {{field['name']}}[{{ field['len'] | int * 3 }}];
                    {# strcpy({{ field['name'] }},{{ onRtnOrderParameters[0]['name'] }}->{{ field['name'] }}); -#}
                    gbk2utf8({{ onRtnOrderParameters[0]['name'] }}->{{ field['name'] }},{{ field['name'] }},sizeof({{ field['name'] }}));
                {% elif field['original'] == 'char' and field['len'] == None -%}
                    {{field['original']}} {{ field['name'] }} = {{ onRtnOrderParameters[0]['name'] }}->{{ field['name'] }};
                {% elif field['original'] != 'char' and field['len'] == None -%}
                    {{field['original']}} {{ field['name'] }} = {{ onRtnOrderParameters[0]['name'] }}->{{ field['name'] }};
                {% else -%}
                    {{ field['name'] }} = ;
                {% endif -%}
            {% endfor %}
        }	

	}

	//{{ onErrRtnOrderInsertMethod['doxygen'].decode('utf8') }}
    virtual {{ onErrRtnOrderInsertMethod['returns'] }} {{ onErrRtnOrderInsertMethod['name'] }}(
        {% for parameter in onErrRtnOrderInsertParameters -%}
            {{  parameter['type'] }} {{ parameter['name'] -}}
            {% if not loop.last %},{% endif %}
        {% endfor -%}
    ){
        printf("{{ onErrRtnOrderInsertMethod['name'] }}():被执行...\n");
        // 如果有返回结果读取返回信息
        if ( {{ onErrRtnOrderInsertParameters[0]['name']}} != NULL ) {
            // 读取返回信息,并做编码转化
            {% for field in onErrRtnOrderInsertFields -%}
                {{field['doxygen'].decode('utf8')}} {{ field['type'] }} {{ field['original'] -}}
                {% if field['len'] %}[{{ field['len'] }}]{% endif %}
                {% if field['enums'] -%}
                    {% for enum in field['enums'] -%}
                        //// {{enum['name']}} {{enum['value']}} {{enum['remark'].decode('utf8')}}
                    {% endfor -%}
                {% endif -%}
                {% if field['original'] == 'char' and field['len'] != None -%}
                    {{field['original']}} {{field['name']}}[{{ field['len'] | int * 3 }}];
                    {# strcpy({{ field['name'] }},{{ onErrRtnOrderInsertParameters[0]['name'] }}->{{ field['name'] }}); -#}
                    gbk2utf8({{ onErrRtnOrderInsertParameters[0]['name'] }}->{{ field['name'] }},{{ field['name'] }},sizeof({{ field['name'] }}));
                {% elif field['original'] == 'char' and field['len'] == None -%}
                    {{field['original']}} {{ field['name'] }} = {{ onErrRtnOrderInsertParameters[0]['name'] }}->{{ field['name'] }};
                {% elif field['original'] != 'char' and field['len'] == None -%}
                    {{field['original']}} {{ field['name'] }} = {{ onErrRtnOrderInsertParameters[0]['name'] }}->{{ field['name'] }};
                {% else -%}
                    {{ field['name'] }} = ;
                {% endif -%}
            {% endfor %}
        }

    }

	
	//{{ onRtnTradeMethod['doxygen'].decode('utf8') }}
    virtual {{ onRtnTradeMethod['returns'] }} {{ onRtnTradeMethod['name'] }}(
        {% for parameter in onRtnTradeParameters -%}
            {{  parameter['type'] }} {{ parameter['name'] -}}
            {% if not loop.last %},{% endif %}
        {% endfor -%}
    ){
		printf("{{ onRtnTradeMethod['name'] }}():被执行...\n");
        // 如果有返回结果读取返回信息
        if ( {{onRtnTradeParameters[0]['name']}} != NULL ) {
            // 读取返回信息,并做编码转化
            {% for field in onRtnTradeFields -%}
                {{field['doxygen'].decode('utf8')}} {{ field['type'] }} {{ field['original'] -}}
                {% if field['len'] %}[{{ field['len'] }}]{% endif %}
                {% if field['enums'] -%}
                    {% for enum in field['enums'] -%}
                        //// {{enum['name']}} {{enum['value']}} {{enum['remark'].decode('utf8')}}
                    {% endfor -%}
                {% endif -%}
                {% if field['original'] == 'char' and field['len'] != None -%}
                    {{field['original']}} {{field['name']}}[{{ field['len'] | int * 3 }}];
                    {# strcpy({{ field['name'] }},{{ onRtnTradeParameters[0]['name'] }}->{{ field['name'] }}); -#}
                    gbk2utf8({{ onRtnTradeParameters[0]['name'] }}->{{ field['name'] }},{{ field['name'] }},sizeof({{ field['name'] }}));
                {% elif field['original'] == 'char' and field['len'] == None -%}
                    {{field['original']}} {{ field['name'] }} = {{ onRtnTradeParameters[0]['name'] }}->{{ field['name'] }};
                {% elif field['original'] != 'char' and field['len'] == None -%}
                    {{field['original']}} {{ field['name'] }} = {{ onRtnTradeParameters[0]['name'] }}->{{ field['name'] }};
                {% else -%}
                    //{{ field['name'] }} = ;
                {% endif -%}
            {% endfor %}
        }

    }


	{{ responseMethod['doxygen'].decode('utf8') }}
	virtual {{ responseMethod['returns'] }} {{ responseMethod['name'] }}(
		{% for parameter in respParameters -%}
			{{ 	parameter['type'] }} {{ parameter['name'] -}}
			{% if not loop.last	%},{% endif %}
		{% endfor -%}
	){		
		printf("{{ responseMethod['name'] }}():被执行...\n");
		
		// 进程返回结果检查
		if ( (pRspInfo) && (pRspInfo->ErrorID != 0) )  {
			// typedef int TThostFtdcErrorIDType;
			// typedef char TThostFtdcErrorMsgType[81];
			char ErrorMsg[243];
			gbk2utf8(pRspInfo->ErrorMsg,ErrorMsg,sizeof(ErrorMsg));
			printf("{{responseMethod['name'] }}():出错:ErrorId=%d,ErrorMsg=%s\n",pRspInfo->ErrorID,ErrorMsg);
		}				

		{# {{respParameters[0]['raw_type']}} responseData; -#}
		// 如果有返回结果读取返回信息
		if ( {{respParameters[0]['name']}} != NULL ) {
			// 读取返回信息,并做编码转化
			{% for field in responseFields -%}
				{{field['doxygen'].decode('utf8')}} {{ field['type'] }} {{ field['original'] -}} 
				{% if field['len'] %}[{{ field['len'] }}]{% endif %}
				{% if field['enums'] -%}
					{% for enum in field['enums'] -%}
						//// {{enum['name']}} {{enum['value']}} {{enum['remark'].decode('utf8')}}
					{% endfor -%}
				{% endif -%}
				{% if field['original'] == 'char' and field['len'] != None -%}
					{{field['original']}} {{field['name']}}[{{ field['len'] | int * 3 }}];
					{# strcpy({{ field['name'] }},{{ respParameters[0]['name'] }}->{{ field['name'] }}); -#}
					gbk2utf8({{ respParameters[0]['name'] }}->{{ field['name'] }},{{ field['name'] }},sizeof({{ field['name'] }}));
				{% elif field['original'] == 'char' and field['len'] == None -%}
					{{field['original']}} {{ field['name'] }} = {{ respParameters[0]['name'] }}->{{ field['name'] }};
				{% elif field['original'] != 'char' and field['len'] == None -%}
					{{field['original']}} {{ field['name'] }} = {{ respParameters[0]['name'] }}->{{ field['name'] }};
				{% else -%}
					//{{ field['name'] }} = ;
				{% endif -%}
			{% endfor %}		
		}
		
		// 如果响应函数已经返回最后一条信息
		if(bIsLast){
			// 通知主过程，响应函数将结束
			sem_post(&sem);
		}	
	}

};


// 定时器控制函数
void timeout_handler(int signalno){
	// 定时控制步骤
}

// 初始化定时器
void init_timer(void)
{
    // init sigaction
    struct sigaction act;
    act.sa_handler = timeout_handler;
    act.sa_flags   = 0;
    sigemptyset(&act.sa_mask);
    sigaction(SIGPROF, &act, NULL);
    // set timer 
    struct itimerval val;
    val.it_value.tv_sec = 1;
    val.it_value.tv_usec = 0;
    val.it_interval = val.it_value;
    setitimer(ITIMER_PROF, &val, NULL);
}


int main(){

	// 初始化线程同步变量
	sem_init(&sem,0,0);

	// 从环境变量中读取登录信息
	char * CTP_FrontAddress = getenv("CTP_FrontAddress");
	if ( CTP_FrontAddress == NULL ){
		printf("环境变量CTP_FrontAddress没有设置\n");
		return(0);
	}
	
	char * CTP_BrokerId = getenv("CTP_BrokerId");
	if ( CTP_BrokerId == NULL ){
		printf("环境变量CTP_BrokerId没有设置\n");
		return(0);
	}
	strcpy(userLoginField.BrokerID,CTP_BrokerId);

	char * CTP_UserId = getenv("CTP_UserId");
	if ( CTP_UserId == NULL ){
		printf("环境变量CTP_UserId没有设置\n");
		return(0);
	}	
	strcpy(userLoginField.UserID,CTP_UserId);

	char * CTP_Password = getenv("CTP_Password");
	if ( CTP_Password == NULL ) {
		printf("环境变量CTP_Password没有设置\n");
		return(0);
	}
	strcpy(userLoginField.Password,CTP_Password);

	// 创建TraderAPI和回调响应控制器的实例
	CThostFtdcTraderApi *pTraderApi = CThostFtdcTraderApi::CreateFtdcTraderApi();
	CTraderHandler traderHandler = CTraderHandler();
	CTraderHandler * pTraderHandler = &traderHandler;
	pTraderApi->RegisterSpi(pTraderHandler);

	// 订阅相关信息推送
    //// THOST_TERT_RESTART:从本交易日开始重传
    //// THOST_TERT_RESUME:从上次收到的续传
    //// THOST_TERT_QUICK:只传送登录后私有流的内容
	pTraderApi->SubscribePrivateTopic(THOST_TERT_RESUME);
    // 订阅公共流
    //// THOST_TERT_RESTART:从本交易日开始重传
    //// THOST_TERT_RESUME:从上次收到的续传
    //// THOST_TERT_QUICK:只传送登录后公共流的内容
	pTraderApi->SubscribePublicTopic(THOST_TERT_RESUME);
	
	// 设置服务器地址
	pTraderApi->RegisterFront(CTP_FrontAddress);
	// 链接交易系统
	pTraderApi->Init();
	// 等待服务器发出登录消息
	sem_wait(&sem);
	// 发出登陆请求
	pTraderApi->ReqUserLogin(&userLoginField, requestID++);
	// 等待登录成功消息
	sem_wait(&sem);

	////////////////////////////////////////////////////////////////////////////////////////////////
	{{requestMethod['doxygen'].decode('utf8')}} 
	///////////////////////////////////////////////////////////////////////////////////////////////
	// 定义调用API的数据结构
	{{reqParameters[0]['raw_type']}} requestData;
	// 确保没有初始化的数据不会被访问
	memset(&requestData,0,sizeof(requestData));
	// 为调用结构题设置参数信息
	{% for field in requestFields -%}
		{{field['doxygen'].decode('utf8')}} {{ field['type'] }} {{ field['original'] -}}
        {% if field['len'] %}[{{ field['len'] }}]{% endif %}
		{% if field['enums'] -%}
			{% for enum in field['enums'] -%}
			//// {{enum['name']}} {{enum['value']}} {{enum['remark'].decode('utf8')}}
			{% endfor -%}
		{% endif -%}
		{% if field['original'] == 'char' and field['len'] != None -%}
			strcpy(requestData.{{ field['name'] }},"");
		{% elif field['original'] == 'char' and field['len'] == None -%}
			requestData.{{ field['name'] }} = '0';
		{% elif field['original'] != 'char' and field['len'] == None -%}
			requestData.{{ field['name'] }} = 0;
		{% else -%}
			//requestData.{{ field['name'] }} = ;
		{% endif -%}
		//////////////////////////////////////////////////////////
	{% endfor %}		

	// 调用API,并等待响应函数返回
	int result = pTraderApi->{{ requestMethod['name'] }}(&requestData,requestID++);
	sem_wait(&sem);	

	/////////////////////////////////////////////////////////////////////////////////////////////////
	

	// 拷贝用户登录信息到登出信息
	strcpy(userLogoutField.BrokerID,userLoginField.BrokerID);
	strcpy(userLogoutField.UserID, userLoginField.UserID);
	pTraderApi->ReqUserLogout(&userLogoutField, requestID++);

	// 等待登出成功
	sem_wait(&sem);

	printf("主线程执行完毕!\n");
	return(0);

}
